WPF Diagrams includes the DiagramXmlSerializer class for saving diagrams to XML and loading them from XML. The DiagramXmlSerializer class works with Diagram objects, ShapeNode, TitleNode and CommentNode nodes, and DiagramConnection connections. If you create a custom diagram type with custom node or connection classes, and you want to use DiagramXmlSerializer to save and load your diagrams, you will need to extend it to handle your custom node or connection classes.

To do this, override the following methods:

The Serialize methods should return a XElement which identifies the type of node or connection in a way that will be recognised by the deserialization methods. The Serialize methods should populate any custom data specified by the node or connection class (this can also be done through the OnSerializeCustomNodeData and OnDeserializeCustomConnectionData callbacks, but these may be set by the user and should therefore not be relied on for essential custom data). The Serialize methods should call the base class implementation if they want default serialization behaviour for the node or connection – note that the DiagramXmlSerializer base implementation handles only the built-in shape, title and comment node types.

Typically you’ll return an empty XElement whose name corresponds to the type of node or connection.
 

CopySerialization support for a custom node type
protected override XElement SerializeNodeCore(DiagramNode node)
{
  if (node is BranchNode)
  {
    return new XElement("BranchNode");
  }
  return base.SerializeNodeCore(node);
}

The Create (deserialize) methods should return an object (node, connection or diagram) appropriate to the XElement passed in. The Create methods should load any custom data specified by the node or connection class (this can also be done through the OnDeserializeCustomNodeData and OnDeserializeCustomConnectionData callbacks, but these may be set by the user and should therefore not be relied on for essential custom data). The Create methods should call the base class implementation if they want the default deserialization behaviour for the XML element.

Typically you’ll switch on the XElement name and return a new node or connection of the appropriate type.
 

CopyDeserialization support for a custom node type
protected override DiagramNode CreateNode(XElement xml)
{
  if (xml.Name.LocalName == "BranchNode")
  {
    return new BranchNode();
  }
  return base.CreateNode(xml);
}

Deserializing custom connection types requires a little more code because connections need to be hooked up to their connection points, and need to call the correct constructor depending on whether there were segments associated with the connection:

CopyDeserialization support for a custom node type
protected override DiagramConnection CreateConnection(XElement xml, DiagramConnectionPoint source, DiagramConnectionPoint destination, IList<DiagramConnectionSegment> segments)
{
  if (xml.Name == ActivityDiagramConnectionElementName)
  {
    if (segments.Count == 0)
    {
      return new ActivityDiagramConnection(source, destination);
    }
    else
    {
      return new ActivityDiagramConnection(source, destination, segments);
    }
  }
  return base.CreateConnection(xml, source, destination, segments);
}